﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Timers;                    // 用于系统定时刷新
using System.IO.Ports;
using System.Threading;
using System.Runtime.CompilerServices;

namespace Com
{
    public partial class Form1 : Form
    {
        //系统定时器
        System.Timers.Timer timer;
        public static int waitTimes = 0;    // 端口发送后等待回收时间
        static bool haveRead = false;       // 已经读取到数据
        static bool timerOut = false;       // 读取等待超时
        static SerialPort serialPort = new SerialPort();
        StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;
        string logFileName = "";            // 保存日志的文件名，如果为空则认为当前没有创建，根据时间创建
        DataLogs dataLogs = new DataLogs();
        //Thread readThread = new Thread(Read);
        const string m_cmdFile = "cmd.txt"; // 保存运行命令到这个文件中

        public Form1()
        {
            InitializeComponent();
            InitParameter();

            // 加载本地保存的命令文件到textBox1.Text
            textBox1.Text = dataLogs.ReadStr(m_cmdFile);

            saveLog.Checked = true;
            dataLogs.CreateDir();

            serialPort.ReadTimeout = 500;
            serialPort.WriteTimeout = 500;

            // 独立线程中访问、修改界面需要这样设置
            Control.CheckForIllegalCrossThreadCalls = false;
        }

        // 将string按照16进制转换成byte
        private bool sendHexDatas(string data, ref byte[] datas)
        {
            // 消息是否正确
            for (int i = 0; i < data.Length; i++)
            {
                // 如果不是数字也不是空格
                if (data[i] != ' ' && ((data[i] < '0' || data[i] > '9') && (data[i] < 'a' || data[i] > 'f')))
                    return false;
            }

            // 空格split后，单个数字不能多余2个字节
            string[] strList = data.Split(' ');
            for (int i = 0; i < strList.Length; i++)
            {
                if (strList[i].Length > 2)
                    return false;
            }

            // 整理发送消息并返回
            int senLen = strList.Length;
            if (haveBr.Checked)
                senLen += 2;
            datas = new byte[senLen];
            if (haveBr.Checked)
            {
                datas[strList.Length] = 13;         // \r
                datas[strList.Length + 1] = 10;     // \n
            }
            for (int i = 0; i < strList.Length; i++)
            {
                datas[i] = Convert.ToByte(strList[i], 16);
            }
            return true;
        }
        private bool isData(string str)
        {
            for (int i = 0; i < str.Length; i++)
                if (str[i] > '9' || str[i] < '0')
                    return false;
            return true;
        }
        public void SaveLog(string log)
        {
            if (logFileName == "")
            {
                // 根据时间创建文件
                logFileName = dataLogs.Save(DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss-ffff" + "\r\n"));
            }
            // 文件中添加log
            dataLogs.Save(log, logFileName);
        }

        /// <summary>
        /// 计算数组的CRC
        /// </summary>
        /// <param name="datas">要校验的数组</param>
        /// <param name="length">字节长度</param>
        /// <returns></returns>
        public UInt16 CheckCRC(byte[] datas, int length)
        {
            if (length > datas.Length)
                length = datas.Length;

            UInt16 crc = 0xffff;
            int pos = 0;
            while (length-- != 0)
            {
                crc ^= datas[pos];
                pos++;
                for (int i = 0; i < 8; i++)
                {
                    if ((crc & 1) == 1)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            return crc;
        }

        private void send_Click(object sender, EventArgs e)
        {
            Task.Run(() => {
                // 回车键
                char[] carriageReturn = new char[] { '\r', '\n' };
                string[] datas = textBox1.Text.Split(carriageReturn);
                // 延时时间
                if (!isData(waitTime.Text) || !isData(timedSendTime.Text))
                {
                    MessageBox.Show("时间设置错误，不是数字");
                    return;
                }
                // 得到发送后等待时间
                int sendNextWaitTime = Convert.ToInt32(timedSendTime.Text);
                int waitReplyTime = Convert.ToInt32(waitTime.Text);
                if (sendNextWaitTime < waitReplyTime)
                {
                    MessageBox.Show("定时发送的时间需要大于事件最多等待时间");
                    return;
                }
                do
                {
                    for (int i = 0; i < datas.Length; i++)
                    {
                        if (datas[i].Length == 0)
                            continue;

                        byte[] sendDatas = new byte[1024];

                        if (hexSend.Checked)
                        {
                            // 如果勾选了16进制发送
                            if (!sendHexDatas(datas[i], ref sendDatas))
                            {
                                MessageBox.Show("发送数据填写错误，如：11 02 33");
                                return;
                            }
                        }
                        else
                        {
                            sendDatas = System.Text.Encoding.Default.GetBytes(datas[i]);
                            if (haveBr.Checked)
                            {
                                Array.Resize(ref sendDatas, sendDatas.Length + 2);
                                sendDatas[sendDatas.Length - 2] = 13;    // \r
                                sendDatas[sendDatas.Length - 1] = 10;    // \n
                            }
                        }
                        // 如果添加CRC校验值
                        if (addCRC.Checked == true)
                        {
                            UInt16 checkCrc = CheckCRC(sendDatas, sendDatas.Length);
                            Array.Resize(ref sendDatas, sendDatas.Length + 2);
                            sendDatas[sendDatas.Length - 2] = (byte)(checkCrc / 256);    // 高八位
                            sendDatas[sendDatas.Length - 1] = (byte)(checkCrc % 256);    // 低八位
                        }
                        if (serialPort.IsOpen)
                        {
                            // 发送数据
                            serialPort.Write(sendDatas, 0, sendDatas.Length);
                            string logs = "发送数据：\r\n" + datas[i];
                            if (addCRC.Checked == true)
                            {
                                logs += " " + Convert.ToString(sendDatas[sendDatas.Length - 2], 16);
                                logs += " " + Convert.ToString(sendDatas[sendDatas.Length - 1], 16);
                            }
                            logs += "\r\n";
                            if (saveLog.Checked)
                            {
                                SaveLog(logs);
                            }
                            this.BeginInvoke(new ReadDelegate(Read), new object[] { logs });
                        }

                        if (receive_mode.Text == "发送后延时")
                        {
                            Thread.Sleep(waitTimes);
                            string indata;
                            int dataLength = serialPort.BytesToRead;
                            if (dataLength > 0)
                            {
                                byte[] buffer = new byte[1024];
                                StringBuilder strBuilder = new StringBuilder();
                                serialPort.Read(buffer, 0, dataLength);
                                if (hexRecv.Checked)
                                {
                                    for (int j = 0; j < dataLength; j++)
                                    {
                                        if (buffer[j] < 16)
                                            strBuilder.Append("0" + buffer[j].ToString("x"));
                                        else
                                            strBuilder.Append(buffer[j].ToString("x"));
                                        strBuilder.Append(" ");
                                    }
                                    indata = "接收内容：\r\n" + strBuilder.ToString() + "\r\n";
                                }
                                else
                                    indata = System.Text.Encoding.Default.GetString(buffer, 0, dataLength);
                            }
                            else
                                indata = "超时未收到\r\n";

                            // 需要触发更新界面
                            if (saveLog.Checked)
                            {
                                SaveLog(indata);
                            }
                            this.BeginInvoke(new ReadDelegate(Read), new object[] { indata });
                        }
                        // 事件处理
                        else
                        {
                            timerOut = false;
                            TimerInit(waitReplyTime);
                            while (!timerOut && !haveRead) ;
                            if (timerOut == true) // 需要触发更新界面
                            {
                                string logs = "超时未收到\r\n";
                                if (saveLog.Checked)
                                {
                                    SaveLog(logs);
                                }
                                this.BeginInvoke(new ReadDelegate(Read), new object[] { logs });
                            }
                            timerOut = false;
                            haveRead = false;
                            timer.Stop();
                        }
                    }

                    if (timedSend.Checked)
                    {
                        Thread.Sleep(sendNextWaitTime);
                    }
                } while (timedSend.Checked && connect.Text == "关闭");
            });
        }

        void DataReceivedHandler(
                        object sender,
                        SerialDataReceivedEventArgs e)
        {
            if (receive_mode.Text == "事件")
            {
                SerialPort sp = (SerialPort)sender;
                int waitTime = 10;
                bool setWaitTimeOK = true;
                for (int i = 0; i < eventWaitTime.Text.Length; i++)
                {
                    // 如果不是数字也不是空格
                    if (eventWaitTime.Text[i] < '0' || eventWaitTime.Text[i] > '9')
                    {
                        setWaitTimeOK = false;
                        break;
                    }
                }
                if (setWaitTimeOK)
                    waitTime = Convert.ToInt32(eventWaitTime.Text);
                Thread.Sleep(waitTime);           // 计算需要多长时间延时后再发送

                int dataLength = serialPort.BytesToRead;
                string indata;
                byte[] buffer = new byte[1024];
                sp.Read(buffer, 0, dataLength);
                StringBuilder strBuilder = new StringBuilder();
                if (hexRecv.Checked) {
                    for (int i = 0; i < dataLength; i++)
                    {
                        if (buffer[i] < 16)
                            strBuilder.Append("0" + buffer[i].ToString("x"));
                        else
                            strBuilder.Append(buffer[i].ToString("x"));
                        strBuilder.Append(" ");
                    }
                    indata = "接收内容：\r\n" + strBuilder.ToString() + "\r\n";
                }
                else
                    indata = "接收内容：\r\n" + System.Text.Encoding.Default.GetString(buffer, 0, dataLength) + "\r\n";
                //indata += sp.ReadExisting();                           // 读取缓冲区全部内容
                // String to store the response ASCII representation.
                //ASCIIEncoding ASCll = new ASCIIEncoding();
                //indata += ASCll.GetString(bt) + "\r\n";
                //indata += Convert.ToString(sp.BytesToRead) + "\r\n";
                haveRead = true;
                // 需要触发更新界面
                if (saveLog.Checked)
                {
                    SaveLog(indata);
                }
                this.BeginInvoke(new ReadDelegate(Read), new object[] { indata });
            }
        }
        private delegate void ReadDelegate(string str);
        private void Read(string str)
        {
            this.textBox2.Text += str; 
            this.textBox2.SelectionStart = this.textBox2.Text.Length;
            this.textBox2.ScrollToCaret();  // 滚动到当前选中位置
            // SaveLog();
        }
        
        private void port_m_SelectedIndexChanged(object sender, EventArgs e)
        {
            
        }

        private void receive_Click(object sender, EventArgs e)
        {
            if(!serialPort.IsOpen)
            {
                connect.Text = "关闭";
                try
                {
                    object myPort;
                    myPort = port_m.SelectedItem;
                    serialPort.PortName = Convert.ToString(myPort);

                    object mySpeed;
                    mySpeed = speed.SelectedItem;
                    serialPort.BaudRate = Convert.ToInt32(mySpeed);

                    string myParity;
                    myParity = odd_even.SelectedItem.ToString();
                    if (myParity == "奇校验")
                        serialPort.Parity = Parity.Odd;
                    else if (myParity == "偶校验")
                        serialPort.Parity = Parity.Even;
                    else
                        serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), Convert.ToString(myParity), true);

                    serialPort.DataBits = 8;

                    object myStop;
                    myStop = stop_num.SelectedItem;
                    serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), Convert.ToString(myStop), true);

                    // 打开串口
                    serialPort.Open();
                }
                catch (Exception ex) {
                    MessageBox.Show("串口打开失败：" + ex.Message);
                    connect.Text = "连接";
                }

                // 连接后开始执行读取线程
                Task.Run(() => {
                    while (false)
                    {
                        if (haveRead)
                        {
                            TimerInit(100);
                            while (haveRead) ;
                        }
                    }
                });
            }
            else
            {
                connect.Text = "连接";
                serialPort.Close();
            }
        }
        void TimerInit(int time)
        {
            //高刷新定时器初始化
            timer = new System.Timers.Timer();
            timer.Interval = time;              // 单位：毫秒
            timer.Elapsed += OnTimedEvent;
            timer.AutoReset = true;
            timer.Enabled = true;
            timer.Start();
            //timer.Stop();
        }
        /* 定时器Timer触发事件
         */
        public void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            timerOut = true;
        }


        private void InitParameter()
        {
            serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

            //comboBox1.Items.Add(textBox1.Text);

            // 查询更新已有端口
            IList<string> list = new List<string>();
            // 读取当前有哪些COM口
            foreach (string s in SerialPort.GetPortNames())
            {
                list.Add(s);
            }
            port_m.DataSource = list;

            // 传输速度
            int[] speed_data = new int[] { 9600, 19200, 38400, 115200 };
            speed.DataSource = speed_data;
            speed.Text = "115200";

            // 奇偶校验
            IList<string> list1 = new List<string>();
            list1.Clear();
            list1.Add("None");
            list1.Add("奇校验");
            list1.Add("偶校验");
            odd_even.DataSource = list1;

            // 停止位
            string[] stop = { "1", "2" };
            stop_num.DataSource = stop;

            //list.Clear();
            string[] str = { "事件", "发送后延时" };
            receive_mode.DataSource = str;             // StopBits

            // 触发事件
            this.port_m.SelectedValueChanged += new System.EventHandler(this.port_m_SelectedIndexChanged);
        }
        // 接收方式发生改变时
        void receive_mode_changed(object ob, EventArgs e) 
        {
            if(receive_mode.Text == "发送后延时")
            {
                DelayTime delayTime = new DelayTime();
                delayTime.Show();
            }
            else
            {
                waitTimes = 0;
            }
        }

        private void clearSend_Click(object sender, EventArgs e)
        {
            textBox1.Text = "";
        }

        private void clearRecv_Click(object sender, EventArgs e)
        {
            textBox2.Text = "";
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            DataLogs dataLogs = new DataLogs();
            dataLogs.Save(this.textBox1.Text, m_cmdFile, System.IO.FileMode.Create);
        }
    }
}
